Migrate Pester test suite from v4 to v5#164
Open
HeyItsGilbert wants to merge 22 commits intomasterfrom
Open
Conversation
- Fix discovery/run phase separation: move all setup code into BeforeAll with $script: scoped variables; TestDrive access likewise moved - Replace `Should be` with `Should -Be` throughout both test files - Migrate Assert-MockCalled to Should -Invoke; remove -Scope It - Replace -ExclusiveFilter (removed in v5) with two-assertion pattern - Move stub function definitions into BeforeAll so they survive the discovery→run phase boundary (Chocolatey, Package types) - Fix Get-ClonedObject: replace BinaryFormatter (removed in .NET 7) with a recursive hashtable clone - Fix Test-PlatformSupport: allow PS Core on Windows to use dependency types that declare Supports = 'windows' (backwards compat) Result: 92 passed, 0 failed, 1 skipped Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* Added `Output/**` and `Tests/Output/**` to `.gitignore` to prevent unnecessary files from being tracked. * Modified `build.ps1` to streamline the invocation of `Invoke-PSDepend` based on the `$Bootstrap` parameter. * Set `RootDir` in `psakeFile.ps1` for Linux compatibility with explicit casing.
* Adjusted the version of `PowerShellBuild` from '0.7.2' to '0.6.1' to maintain compatibility with the current setup.
* Reformatted YAML for consistency in spacing. * Separated Bootstrap and Test steps for clarity in the CI process.
* Changed `properties` to `Properties` for consistency. * Removed unnecessary task definitions and streamlined the `Test` task. * Adjusted comments for clarity regarding CI behavior.
PowerShellBuild 0.6.1 has no mechanism to override the Build task's dependency chain from outside its psake file. 0.7.x introduced $PSBBuildDependency which can be pre-set before -FromModule loads the module, preventing BuildHelp (and GenerateMarkdown) from running. GenerateMarkdown is not needed in the test pipeline and Build-PSBuildMarkdown has a Remove-Module scope issue specific to PSDepend that causes it to attempt removing 'platyPS' instead of 'PSDepend', failing because platyPS is required by PowerShellBuild. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…exts Bare Set-StrictMode calls in Context block bodies run during Pester 5's discovery phase, not test execution — the It blocks never actually ran under strict mode. Wrapping in BeforeAll/AfterAll ensures strict mode applies during execution and is cleaned up after each context. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Four related fixes in one pass: 1. Prefix all outer Describe BeforeAll variables with $script: so they are visible in It blocks during test execution. 2. Prefix all inner Context BeforeAll variables with $script: and update the three parameter-validation It assertions to use $script: reads. 3. Add $helpParameters/$helpParameterNames to BeforeDiscovery so that -ForEach $helpParameterNames on the inner Context is non-empty at discovery time (BeforeAll runs too late for ForEach evaluation). 4. Replace undefined $parameterNames with $script:commandParameterNames. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Mocks defined inside It blocks are scoped to that It and collapse when it exits, making Should -Invoke assertions fragile and mixing arrangement with assertion. Moved mocks to BeforeAll for the five affected contexts (PSGalleryModule Imports, AddToPath-install, SkipPublisherCheck, AllowPrerelease; PSGalleryNuget Imports, AddToPath-install) and added -Scope Context to all Should -Invoke calls in those contexts. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The two AddToPath-install contexts (PSGalleryModule and PSGalleryNuget) restored $ENV:PSModulePath inside the It body. If the assertion before that line failed, the env var would remain modified for the rest of the run. Moved cleanup to AfterEach so it runs unconditionally. Also switched to explicit $script:ExistingPSModulePath to match how the variable is set in the outer BeforeAll. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Invoke-WebRequest had no timeout, causing the suite to hang on slow or unreachable URLs. Added -TimeoutSec 10. Tagged the It blocks -Tag 'Acceptance' so offline CI runs can exclude them with -ExcludeTag Acceptance. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Git, FileDownload, and FileSystem Describe blocks all skip on non-Windows via -Skip:\$nonWindows. The Chocolatey block only had -Tag 'WindowsOnly', meaning it would still execute on Linux/macOS runners unless callers explicitly excluded the tag. Aligned it with the other Windows-only blocks. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The 'Installs Packages' Context was commented out pending Pester issue #604 (mock parameter binding), which is resolved in Pester 5. Rewrote it with BeforeAll, $script: variables, and -Scope Context. Removed -Skip and the stale AppVeyor comment from 'Latest package required' — the flakiness was caused by mock bleeding across contexts, which Pester 5 scope isolation eliminates. Also moved all inline Mock calls from It bodies in 'Same package version exists' and the latest context into BeforeAll blocks. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Cover three scenarios missing from the existing success-path suite: - -Tags filter returns only dependencies with matching tags - -Tags with no match returns nothing - -InputObject hashtable is parsed as PSGalleryModule by default Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…l-Dependency, Invoke-DependencyScript Four previously untested public functions now have dedicated Describe blocks: - Get-PSDependType: returns typed objects, filters by wildcard, Supported is bool, throws on invalid path - Get-PSDependScript: returns hashtable, all values are real paths, throws on invalid path - Install-Dependency: pipeline from Get-Dependency calls Install-Module - Invoke-DependencyScript: Command type returns output, non-existent action warns rather than throws, Test action with -Quiet returns bool Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add .EXAMPLE to Get-Dependency help (fixes help test failures) - Fix .LINK URL typo PowerShellOr -> PowerShellOrg across all public functions - Filter null URIs in Help.tests.ps1 to prevent FunctionInfo-as-Uri errors when .LINK entries are non-URL (function names, about pages) - Strip -Force from PSBoundParameters before splatting to Invoke-DependencyScript, which has no -Force parameter - Add -ModuleName PSDepend to all Mock/-Invoke assertions for commands called from within PSDepend dependency scripts (Install-Module, Save-Module, Get-Module, Find-Module, Import-Module, Get-PSRepository, Install-Package, Get-Package, Find-Package, Get-PackageSource, Get-NodeModule, Install-NodeModule, Test-Dotnet, Install-Dotnet, Get-DotnetVersion, Get-Command, Test-Path) so Pester v5 intercepts them at the correct module scope Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Use @{} + $PSBoundParameters instead of .Clone() to copy PSBoundParameters
into a mutable hashtable (PSBoundParametersDictionary has no Clone method)
- Inject stub functions for PackageManagement commands into PSDepend's module
scope via & (Get-Module PSDepend) { ... } so -ModuleName PSDepend mocks
can resolve them; remove now-redundant inline function redefinitions in
individual Package contexts; add AfterAll cleanup
- Add -ModuleName PSDepend to all mocks in Git, FileDownload, PSGalleryNuget,
and FileSystem Describe blocks — these are Windows-only sections where
Invoke-ExternalCommand, Get-WebFile, Find-NugetPackage, Copy-Item,
Import-LocalizedData, Import-Module, Test-Path, New-Item, Push-Location,
Pop-Location, and Set-Location all resolve inside PSDepend's module scope
- Fix Npm: add -ModuleName PSDepend to Push-Location and Pop-Location in
both Npm contexts; fix `return true` string bug to `return $true`
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Package: add [cmdletbinding()]param() to Get-PackageSource stub so Pester
can generate a valid v5 mock proxy without ParameterBindingException
- Package: add Mock Get-PackageSource -ModuleName PSDepend to the three
contexts that were hitting the real cmdlet (Same version, Latest, Test-Dependency)
- Npm: fix ParameterFilter from { $Target -eq 'Global' } to { $Global -eq $true };
Npm.ps1 calls Get-NodeModule -Global (switch), not -Target 'Global'
- Chocolatey 'installs Chocolatey': add -ModuleName PSDepend to Get-Command
and Invoke-WebRequest mocks and Should -Invoke assertions
- Chocolatey skip/install contexts: replace unmockable inline helpers
(Get-ChocoInstalledPackage, Get-ChocoLatestPackage, Invoke-ChocoInstallPackage)
with Invoke-ExternalCommand mocks; the inline functions are dot-sourced into
local scope and shadow module-scope mocks, but Invoke-ExternalCommand is a
PSDepend private module function that Pester can intercept; use ParameterFilter
on --local-only (installed), list-no-local-only (latest), and upgrade (install)
to distinguish the three call types and return appropriate CSV-formatted data
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Without the script: scope qualifier, function definitions inside
& (Get-Module PSDepend) { function Foo { } } are created in a temporary
scope that vanishes when the scriptblock returns. The stubs were never
actually shadowing the real cmdlets.
Pester's mock proxy was being generated from the real Get-Package /
Install-Package / Find-Package / Get-PackageSource cmdlets (from
AnyPackage on Linux, PackageManagement elsewhere) — whose multi-parameter
-set definitions failed to bind our test splats with
ParameterBindingException: Parameter set cannot be resolved.
Using function script:Foo persists the stub in the module's script scope
so Get-Command -Module PSDepend resolves to the stub, and Pester generates
the proxy from the stub's simple param signature.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR migrates the repository’s PowerShell test suite and build pipeline to be compatible with Pester v5 / PS7+, while addressing PS7-specific runtime issues (deep cloning and platform support checks).
Changes:
- Migrates
PSDepend.Tests.ps1andPSModuleGallery.Type.Tests.ps1to Pester 5 syntax/scoping and updates mocking/assertions accordingly. - Replaces
.NET BinaryFormatterusage with a recursive hashtable clone implementation and adjusts platform support logic for PS Core on Windows. - Updates build/CI configuration (PowerShellBuild version bump, psake/CI workflow adjustments) and adds a help validation test suite.
Reviewed changes
Copilot reviewed 17 out of 18 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| requirements.psd1 | Bumps PowerShellBuild dependency version. |
| psakeFile.ps1 | Updates PowerShellBuild task wiring and test root configuration. |
| build.ps1 | Imports requirements during non-bootstrap runs. |
| Tests/PSModuleGallery.Type.Tests.ps1 | Migrates integration tests to Pester 5 and updates mocks/assertions. |
| Tests/PSDepend.Tests.ps1 | Migrates unit tests to Pester 5 and adds new unit coverage. |
| Tests/Help.tests.ps1 | Adds command help validation tests. |
| PSDepend/Public/Test-Dependency.ps1 | Formatting + help link cleanup. |
| PSDepend/Public/Invoke-PSDepend.ps1 | Help link cleanup. |
| PSDepend/Public/Invoke-DependencyScript.ps1 | Formatting + help link cleanup. |
| PSDepend/Public/Install-Dependency.ps1 | Avoids splatting Force into Invoke-DependencyScript. |
| PSDepend/Public/Import-Dependency.ps1 | Help link cleanup. |
| PSDepend/Public/Get-PSDependType.ps1 | Help link cleanup. |
| PSDepend/Public/Get-PSDependScript.ps1 | Formatting + minor style cleanup. |
| PSDepend/Public/Get-Dependency.ps1 | Help updates + refactor formatting (includes a small comment typo). |
| PSDepend/Private/Test-PlatformSupport.ps1 | Treats Supports='windows' as sufficient on Windows+Core. |
| PSDepend/Private/Get-ClonedObject.ps1 | Replaces BinaryFormatter deep clone with recursive hashtable clone. |
| .gitignore | Ignores build output folders. |
| .github/workflows/ci.yml | Splits bootstrap and test steps in CI. |
Comments suppressed due to low confidence (1)
psakeFile.ps1:34
psakeFile.ps1no longer defines anInittask, but the repo still calls./build.ps1 -Task Init(tests and CI). With onlyDefaultandTesttasks defined here,Invoke-Psake -TaskList Initwill fail. Either reintroduce anInittask (e.g.,Task Init -FromModule PowerShellBuild ...) or update all callers to use an existing task (such asTest/Default) that performs the required staging/build environment setup.
Task Default -Depends Test
Task Test -FromModule PowerShellBuild -MinimumVersion '0.7.3'
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
* Updated the path for uploading test results from `./Output/testResults.xml` to `./Tests/out/testResults.xml` to ensure proper artifact handling.
HeyItsGilbert
commented
May 3, 2026
* Fixed LicenseUri and ProjectUri in `PSDepend.psd1` and `about_PSDepend.help.txt` to point to the correct GitHub organization.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
PSDepend.Tests.ps1andPSModuleGallery.Type.Tests.ps1to Pester 5 — all setup code moved intoBeforeAllblocks with$script:scoped variables, assertion syntax updated (Should be→Should -Be),Assert-MockCalledreplaced withShould -Invoke,-ExclusiveFilterreplaced with a two-assertion pattern,-Scope Itremoved, stub function definitions moved intoBeforeAllso they survive the discovery→run phase boundaryGet-ClonedObject.ps1: ReplacedBinaryFormatter(removed in .NET 7) with a recursive hashtable deep-clone — fixes 2 test failures on PS7Test-PlatformSupport.ps1: Added a PS Core on Windows exemption so dependency types that declareSupports = 'windows'(FileDownload, FileSystem, Chocolatey) are no longer incorrectly skipped under PS7 Core on Windows — fixes 12 test failuresResult: 92 passed, 0 failed, 1 skipped (the 1 skip is a pre-existing
PendingSkiptag, not a regression)Test plan
Invoke-Pester ./Tests -Output Detailedlocally — 92 passed, 0 failed🤖 Generated with Claude Code